#include "crossbit/ELFMemoryImage.h"
#include "crossbit/VInst.h"

#include "arch/mips/MIPSInterpreter.h"
#include "arch/mips/MIPSVBasicBlockBuilder.h"

#include "MIPSInst.h"

using namespace crossbit;

namespace crossbit
{
#define INSTLEN		4

#define DELAYREG1	34
#define DELAYREG2	35
#define TEMPREG1	36
#define TEMPREG2	37
#define TEMPREG3	38 
#define TEMPREG4	39
#define TEMPREG5	40

/*
#define TEMPREG1	136
#define TEMPREG2	137
#define TEMPREG3	138 
#define TEMPREG4	139
#define TEMPREG5	140


		ShadowPage *pShadowPage;

		void readMem(XTMemAddr addr, XTInt32 size)
		{
				pShadowPage -> readMem( addr, size );
		}

		void writeMem(XTMemAddr addr, XTInt32 size, XTUint32 value)
		{
				pShadowPage -> writeMem( addr, size, value );
		}


#define LD_MEM(base, disp, size, dest) \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((disp), TEMPREG1) ); \
		if( base != 0 ) \
		((MIPSVBasicBlockBuilder*)arg)->add( ADD( base, TEMPREG1, TEMPREG1) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((int)size, TEMPREG2) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( CALL((XTMemAddr)(&crossbit::readMem), 2, TEMPREG1, TEMPREG2) );

#define ST_MEM(value, size, base, disp) \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((disp), TEMPREG1) ); \
		if( base != 0 ) \
		((MIPSVBasicBlockBuilder*)arg)->add( ADD( base, TEMPREG1, TEMPREG1) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((int)size, TEMPREG2) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( CALL((XTMemAddr)(&crossbit::writeMem), 3, TEMPREG1, TEMPREG2, value) );

#define FST_MEM(value, size, base, disp) \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((disp), TEMPREG1) ); \
		if( base != 0 ) \
		((MIPSVBasicBlockBuilder*)arg)->add( ADD( base, TEMPREG1, TEMPREG1) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( LI((int)size, TEMPREG2) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( LI(pState->fpGet(value), TEMPREG3) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG3, 0, WORD, TEMPREG3 ) ); \
		((MIPSVBasicBlockBuilder*)arg)->add( CALL((XTMemAddr)(&crossbit::writeMem), 3, TEMPREG1, TEMPREG2, TEMPREG3) );
*/

		MIPSOpsFmt* pInst;
		MIPSProcessorState *pState;
		XTMemAddr PC;
		
		void deSpecial(void* arg);
		void deRegimm(void* arg);
		void deJ(void* arg);
		void deJAL(void* arg);
		void deBEQ(void* arg);
		void deBNE(void* arg);
		void deBLEZ(void* arg);
		void deBGTZ(void* arg);
		void deADDI(void* arg);
		void deADDIU(void* arg);
		void deSLTI(void* arg);
		void deSLTIU(void* arg);
		void deANDI(void* arg);
		void deORI(void* arg);
		void deXORI(void* arg);
		void deLUI(void* arg);
		void deCOP0(void* arg);
		void deCOP1(void* arg);
		void deCOP2(void* arg);
		void deCOP1X(void* arg);
		void deBEQL(void* arg);
		void deBNEL(void* arg);
		void deBLEZL(void* arg);
		void deBGTZL(void* arg);
		void deSpecial2(void* arg);
		void deJALX(void* arg);
		void deSpecial3(void* arg);
		void deLB(void* arg);
		void deLH(void* arg);
		void deLWL(void* arg);
		void deLW(void* arg);
		void deLBU(void* arg);
		void deLHU(void* arg);
		void deLWR(void* arg);
		void deSB(void* arg);
		void deSH(void* arg);
		void deSWL(void* arg); 
		void deSW(void* arg);
		void deSWR(void* arg);
		void deLL(void* arg);
		void deLWC1(void* arg);
		void deLWC2(void* arg);
		void dePREF(void* arg);
		void deLDC1(void* arg);
		void deLDC2(void* arg);
		void deSC(void* arg);
		void deSWC1(void* arg);
		void deSWC2(void* arg);
		void deSDC1(void* arg);
		void deSDC2(void* arg);
		void deUndef(void* arg);

		void deSLL(void* arg);
		void deMOVCI(void* arg);
		void deSRL(void* arg);
		void deSRA(void* arg);
		void deSLLV(void* arg);
		void deSRLV(void* arg);
		void deSRAV(void* arg);
		void deJR(void* arg);	//JR, JR.HB
		void deJALR(void* arg);	//JALR, JALR.HB
		void deMOVZ(void* arg);
		void deMOVN(void* arg);
		void deSYSCALL(void* arg);
		void deBREAK(void* arg);
		void deSYNC(void* arg);
		void deMFHI(void* arg);
		void deMTHI(void* arg);
		void deMFLO(void* arg);
		void deMTLO(void* arg);
		void deMULT(void* arg);
		void deMULTU(void* arg);
		void deDIV(void* arg);
		void deDIVU(void* arg);
		void deADD(void* arg);
		void deADDU(void* arg);
		void deSUB(void* arg);
		void deSUBU(void* arg);
		void deAND(void* arg);
		void deOR(void* arg);
		void deXOR(void* arg);
		void deNOR(void* arg);
		void deSLT(void* arg);
		void deSLTU(void* arg);
		void deTGE(void* arg);
		void deTGEU(void* arg);
		void deTLT(void* arg);
		void deTLTU(void* arg);
		void deTEQ(void* arg);
		void deTNE(void* arg);

		void deBLTZ(void* arg);
		void deBGEZ(void* arg);
		void deBLTZL(void* arg);
		void deBGEZL(void* arg);
		void deTGEI(void* arg);
		void deTGEIU(void* arg);
		void deTLTI(void* arg);
		void deTLTIU(void* arg);
		void deTEQI(void* arg);
		void deTNEI(void* arg);
		void deBLTZAL(void* arg);
		void deBGEZAL(void* arg);
		void deBLTZALL(void* arg);
		void deBGEZALL(void* arg);
		void deSYNCI(void* arg);

		//COP1
		void deCOP1S(void* arg);
		void deMFC1(void* arg);
		void deCFC1(void* arg);
		void deMTC1(void* arg);
		void deCTC1(void* arg);
		void deBC1(void* arg);
		void deCOP1D(void* arg);
		void deCOP1W(void* arg);

		void deADD_S(void* arg);
		void deADD_D(void* arg);
		void deSUB_S(void* arg);
		void deSUB_D(void* arg);
		void deDIV_S(void* arg);
		void deDIV_D(void* arg);
		void deMUL_S(void* arg);
		void deMUL_D(void* arg);
		void deABS_S(void* arg);
		void deABS_D(void* arg);
		void deMOV_S(void* arg);
		void deMOV_D(void* arg);
		void deNEG_S(void* arg);
		void deNEG_D(void* arg);
		void deCVT_W_D(void* arg);
		void deC_EQ_S(void* arg);
		void deC_EQ_D(void* arg);
		void deC_ULE_S(void* arg);
		void deC_LT_S(void* arg);
		void deC_LT_D(void* arg);
		void deC_LE_S(void* arg);
		void deC_LE_D(void* arg);

		void deCVT_D_S(void* arg);
		void deCVT_W_S(void* arg);
		void deCVT_S_W(void* arg);
		void deCVT_D_W(void* arg);

		void deCVT_S_D(void* arg);

		typedef void (*Defunc)(void*);

		typedef struct
		{
				XTPStr name;
				Defunc f;
		} FuncTable;

		FuncTable deTable[] = 
		{ 											//op:
				{"SPECIAL", deSpecial}, {"REGIMM", deRegimm}, {"J", deJ}, {"JAL", deJAL},	//0 - 4
				{"BEQ", deBEQ}, {"BNE", deBNE}, {"BLEZ", deBLEZ}, {"BGTZ", deBGTZ},
				{"ADDI", deADDI}, {"ADDIU", deADDIU}, {"SLTI", deSLTI}, {"SLTIU", deSLTIU},
				{"ANDI", deANDI}, {"ORI", deORI}, {"XORI", deXORI}, {"LUI", deLUI},
				{"Undef", deUndef},{"COP1", deCOP1},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},	
				{"LB", deLB},{"LH", deLH},{"LWL", deLWL},{"LW", deLW},
				{"LBU", deLBU},{"LHU", deLHU},{"LWR", deLWR},{"Undef", deUndef},
				{"SB", deSB},{"SH", deSH},{"SWL", deSWL},{"SW", deSW},
				{"Undef", deUndef},{"Undef", deUndef},{"SWR", deSWR},{"Undef", deUndef},
				{"LL", deLL},{"LWC1", deLWC1},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"SC", deSC},{"SWC1", deSWC1},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
		};

		FuncTable deSpecialTable[] = 
		{
				{"SLL", deSLL},{"Undef", deUndef},{"SRL", deSRL},{"SRA", deSRA},
				{"SLLV", deSLLV},{"Undef", deUndef},{"SRLV", deSRLV},{"SRAV", deSRAV},
				{"JR", deJR},{"JALR", deJALR},{"Undef", deUndef},{"Undef", deUndef},
				{"SYSCALL", deSYSCALL},{"BREAK", deBREAK},{"Undef", deUndef},{"Undef", deUndef},
				{"MFHI", deMFHI},{"Undef", deUndef},{"MFLO", deMFLO},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"MULT", deMULT},{"MULTU", deMULTU},{"DIV", deDIV},{"DIVU", deDIVU},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"ADDU", deADDU},{"Undef", deUndef},{"SUBU", deSUBU},
				{"AND", deAND},{"OR", deOR},{"XOR", deXOR},{"NOR", deNOR},
				{"Undef", deUndef},{"Undef", deUndef},{"SLT", deSLT},{"SLTU", deSLTU},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
		};

		FuncTable deRegimmTable[]  = 
		{
				{"BLTZ", deBLTZ},{"BGEZ", deBGEZ},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"BLTZAL", deBLTZAL},{"BGEZAL", deBGEZAL},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
		};

		FuncTable deCOP1Table[] = 
		{
				{"MFC1", deMFC1},{"Undef", deUndef},{"CFC1", deCFC1},{"Undef", deUndef},
				{"MTC1", deMTC1},{"Undef", deUndef},{"CTC1", deCTC1},{"Undef", deUndef},
				{"BC1", deBC1},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"cop1s", deCOP1S},{"cop1d", deCOP1D},{"Undef", deUndef},{"Undef", deUndef},
				{"cop1w", deCOP1W},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
		};

		FuncTable deCOP1STable[]  =
		{
				{"ADD.S", deADD_S},{"SUB.S", deSUB_S},{"MUL_S", deMUL_S},{"DIV.S", deDIV_S},
				{"Undef", deUndef},{"ABS.S", deABS_S},{"MOV.S", deMOV_S},{"NEG.S", deNEG_S},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"CVT.D.S", deCVT_D_S},{"Undef", deUndef},{"Undef", deUndef},
				{"CVT.W.S", deCVT_W_S},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"C.EQ.S", deC_EQ_S},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"C.ULE.S", deC_ULE_S},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"C.LT.S", deC_LT_S},{"Undef", deUndef},{"C.LE.S", deC_LE_S},{"Undef", deUndef}
		};

		FuncTable deCOP1DTable[]  =
		{
				{"ADD.D", deADD_D},{"SUB.D", deSUB_D},{"MUL_D", deMUL_D},{"DIV_D", deDIV_D},
				{"Undef", deUndef},{"ABS.D", deABS_D},{"MOV.D", deMOV_D},{"NEG.D", deNEG_D},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"CVT.S.D", deCVT_S_D},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"CVT.W", deCVT_W_D},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"C.EQ", deC_EQ_D},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"C.LT", deC_LT_D},{"Undef", deUndef},{"C.LE", deC_LE_D},{"Undef", deUndef}
		};

		FuncTable deCOP1WTable[]  =
		{
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"CVT.S.W", deCVT_S_W},{"CVT.D", deCVT_D_W},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},
				{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef},{"Undef", deUndef}
		};


		void deSpecial(void* arg)
		{
				deSpecialTable[pInst->func].f(arg);
		}

		void deRegimm(void* arg)
		{
				deRegimmTable[pInst->bl].f(arg);
		}

		void deCOP1(void* arg)
		{
				deCOP1Table[pInst->rs].f(arg);
		}

		void deCOP1S(void* arg)
		{
				deCOP1STable[pInst->func].f(arg);
		}

		void deCOP1D(void* arg)
		{
				deCOP1DTable[pInst->func].f(arg);
		}

		void deCOP1W(void* arg)
		{
				deCOP1WTable[pInst->func].f(arg);
		}

		void deJ(void* arg)
		{/*
			unsigned int w = *((unsigned int*)arg);
			unsigned target = ((w&0x03ffffff) << 2) |((PC+INSTLEN)&0xf0000000);
		  */
				printf("0x%08x\n", PC);
				exit(1);
		}

		void deJAL(void* arg)
		{
				printf("0x%08x\n", PC);
				exit(1);
		}

		void deBEQ(void* arg)
		{
				unsigned address = PC + 4 + ((signed short)pInst->offset <<2 );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rt, DELAYREG2) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(EQ, DELAYREG1, DELAYREG2, 0, address) );

				PC = PC + 4;
		}

		void deBNE(void* arg)
		{
				unsigned address = PC + 4 + ((signed short)pInst->offset <<2 );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rt, DELAYREG2) );

				pInst = (MIPSOpsFmt*)(PC+4);

				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(NE, DELAYREG1, DELAYREG2, 0, address) );

				PC = PC + 4;
		}

		void deBLEZ(void* arg)
		{
				unsigned address = PC + 4 + ((signed short)pInst->offset << 2 );

				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LE, DELAYREG1, 0, 0, address) );

				PC = PC + 4;
		}

		void deBGTZ(void* arg)
		{
				unsigned address = PC + 4 + ((signed short)pInst->offset << 2 );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GT, DELAYREG1, 0, 0, address) );
				PC = PC + 4;
		}

		void deADDI(void* arg)
		{
				printf("0x%08x\n", PC);
				exit(1);
		}

		void deADDIU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI(((int)(signed short)pInst->offset), TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD( TEMPREG1, pInst->rrs, pInst->bl) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->bl, pInst->bl) );
		}

		void deSLTI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI((int)(signed short)pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( CMP(LT, pInst->rs, TEMPREG1, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rt, pInst->rt) );
		}

		void deSLTIU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI((int)(signed short)pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( CMP(BE, pInst->rs, TEMPREG1, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rt, pInst->rt) );
		}

		void deANDI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, pInst->rs, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deORI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG1, pInst->rrs, pInst->bl) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) );
		}

		void deXORI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( XOR(TEMPREG1, pInst->rs, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deLUI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI((pInst->offset<<16), pInst->bl) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl));
		}

		void deLB(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rs, 
														 ((int)(signed short)pInst->offset), BYTE, pInst->rt) );        
				//LD_MEM( pInst->rs, ((int)(signed short)pInst->offset), BYTE, pInst->rt );        
				((MIPSVBasicBlockBuilder*)arg)->add( SEXT(pInst->rt, BYTE, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) ); 
		}

		void deLH(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(pInst->rs,
														((int)(signed short)pInst->offset), HALFWORD, pInst->rt));
				//LD_MEM( pInst->rs, ((int)(signed short)pInst->offset), HALFWORD, pInst->rt );        
				((MIPSVBasicBlockBuilder*)arg)->add( SEXT(pInst->rt, HALFWORD, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deLWL(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG5, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG2, 0, WORD, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG5, TEMPREG1, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG5, TEMPREG1, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(24, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( SUB(TEMPREG3, TEMPREG5, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG2, TEMPREG3, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG4, TEMPREG3, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG4, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rt, TEMPREG4, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rt, TEMPREG2, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deLWR(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG2, 0, WORD, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG4, TEMPREG1, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG2, TEMPREG4, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG3, TEMPREG4, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG3, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rt, TEMPREG3, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rt, TEMPREG2, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deLW(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rrs, 
														 ((int)(signed short)pInst->offset), WORD, pInst->bl) );        
				//LD_MEM( pInst->rrs, ((int)(signed short)pInst->offset), WORD, pInst->bl );        
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) ); 
		}

		void deLBU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(pInst->rs, 
														((int)(signed short)pInst->offset), BYTE, pInst->rt) );
				//LD_MEM( pInst->rs, ((int)(signed short)pInst->offset), BYTE, pInst->rt );        
				((MIPSVBasicBlockBuilder*)arg)->add( ZEXT(pInst->rt, BYTE, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deLHU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rs, 
														 ((int)(signed short)pInst->offset), HALFWORD, pInst->rt) );        
				//LD_MEM( pInst->rs, ((int)(signed short)pInst->offset), HALFWORD, pInst->rt );        
				((MIPSVBasicBlockBuilder*)arg)->add( ZEXT(pInst->rt, HALFWORD, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) ); 
		}

		void deSB(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, BYTE, pInst->rs, ((int)(signed short)pInst->offset)) );
				//ST_MEM(pInst->rt, BYTE, pInst->rs, ((int)(signed short)pInst->offset));

		}

		void deSH(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, HALFWORD, pInst->rs, ((int)(signed short)pInst->offset)) );
				//ST_MEM(pInst->rt, HALFWORD, pInst->rs, ((int)(signed short)pInst->offset));
		}

		void deSWL(void* arg)	//added newly
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, TEMPREG2, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG3, 0, WORD, TEMPREG4) );
				//LD_MEM(TEMPREG3, 0, WORD, TEMPREG4);
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG1, TEMPREG2, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG1, TEMPREG2, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(24, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( SUB(TEMPREG2, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG2, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(TEMPREG1, TEMPREG2, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG1, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG4, TEMPREG5, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(TEMPREG4, WORD, TEMPREG3, 0) );
				//ST_MEM(TEMPREG4, WORD, TEMPREG3, 0);
		}

		void deSWR(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xfffffffc, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG2, TEMPREG1, TEMPREG3) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(TEMPREG3, 0, WORD, TEMPREG4) );
				//LD_MEM(TEMPREG3, 0, WORD, TEMPREG4);
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->offset, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x3, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG2, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG2, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG2, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0xffffffff, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(TEMPREG1, TEMPREG2, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( NOT(TEMPREG1, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(TEMPREG4, TEMPREG1, TEMPREG4) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(TEMPREG5, TEMPREG4, TEMPREG5) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(TEMPREG5, WORD, TEMPREG3, 0) );
				//ST_MEM(TEMPREG5, WORD, TEMPREG3, 0);
		}

		void deLL(void* arg)	//an atomic read, simply equal lw now
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD( pInst->rrs, 
														 ((int)(signed short)pInst->offset), WORD, pInst->bl) );        
				//LD_MEM( pInst->rrs, ((int)(signed short)pInst->offset), WORD, pInst->bl );        
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) ); 
		}

		void deLWC1(void* arg)	//added newly
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( FLD(pInst->rs, 
														 ((int)(signed short)pInst->offset), WORD, pInst->rt) );
				//LD_MEM( pInst->rs, ((int)(signed short)pInst->offset), WORD, pInst->rt );        
		}

		void deSC(void* arg)	//an atomic write, simply equal sw now
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->bl, pInst->bl) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->bl, WORD, pInst->rrs, ((int)(signed short)pInst->offset)) );
				//ST_MEM(pInst->bl, WORD, pInst->rrs, ((int)(signed short)pInst->offset));
				((MIPSVBasicBlockBuilder*)arg)->add( LI(1, pInst->bl) );
				//((MIPSVBasicBlockBuilder*)arg)->add( MOV(TEMPREG1, pInst->bl));
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->bl, pInst->bl) );
		}

		void deSWC1(void* arg)	//added newly
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				//FST_MEM(pInst->rt, WORD, pInst->rs, ((int)(signed short)pInst->offset));
				((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rt, WORD, pInst->rs, ((int)(signed short)pInst->offset)) );

		}

		void deSW(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->bl, pInst->bl) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->bl, WORD, pInst->rrs, ((int)(signed short)pInst->offset)) );
				//ST_MEM(pInst->bl, WORD, pInst->rrs, ((int)(signed short)pInst->offset));
		}

		void deSLL(void* arg)
		{
				if( pInst->ze == 0 && pInst->rt == 0 && pInst->rd == 0 )
				{
						//do nothing
				}
				else if( pInst->ze == 1 && pInst->rt == 0 && pInst->rd == 0 )
				{
						//do nothing
				}
				else
				{
						((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
						((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt));
						((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG1, pInst->rd) );
						((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd));
				}
		}

		void deMOVCI(void* arg);

		void deSRL(void* arg)	//don't consider ROTR
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG1, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSRA(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(pInst->ze, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRA(pInst->rt, TEMPREG1, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSLLV(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( SLL(pInst->rt, TEMPREG2, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSRLV(void* arg)
		{	
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, TEMPREG1, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRL(pInst->rt, TEMPREG2, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSRAV(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( LI(0x1f, TEMPREG1) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND( TEMPREG1, pInst->rs, TEMPREG2) );
				((MIPSVBasicBlockBuilder*)arg)->add( SRA(pInst->rt, TEMPREG2, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deJR(void* arg)	//JR, JR.HB
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( JMP(DELAYREG1, 0) );

				PC = PC + 4;
		}

		void deMOVZ(void* arg);
		void deMOVN(void* arg);
		void deSYSCALL(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( SYSCALL );
		}

		void deBREAK(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( HALT(PC) );
		}

		void deSYNC(void* arg);

		void deMFHI(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(32, 32) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(32, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deMTHI(void* arg);

		void deMFLO(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(33, 33) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(33, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deMTLO(void* arg);
		void deMULT(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( MUL(pInst->rs, pInst->rt, 32, 33) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
		}

		void deMULTU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( MULU(pInst->rs, pInst->rt, 32, 33) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
		}

		void deDIV(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( DIV(pInst->rs, pInst->rt, 33, 32) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
		}

		void deDIVU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( DIVU(pInst->rs, pInst->rt, 33, 32) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(33, 33) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(32, 32) );
		}

		void deADD(void* arg);
		void deSUB(void* arg);

		void deSUBU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( SUB(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deOR(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deXOR(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( XOR(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deNOR(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( OR(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( NOT(pInst->rd, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSLT(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( CMP(LT, pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deSLTU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( CMP(BE, pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deTGE(void* arg);
		void deTGEU(void* arg);
		void deTLT(void* arg);
		void deTLTU(void* arg);
		void deTEQ(void* arg);
		void deTNE(void* arg);


		void deJALR(void* arg) //JALR, JALR.HB
		{
				((MIPSVBasicBlockBuilder*)arg)->add( LI((PC+8), pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT( pInst->rd, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET( pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV( pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( JMP(DELAYREG1,0) );

				PC = PC + 4;
		}

		void deADDU(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( ADD(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deAND(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( AND(pInst->rs, pInst->rt, pInst->rd) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rd, pInst->rd) );
		}

		void deBLTZ(void* arg)
		{
				unsigned address = (PC+4+(((signed short)pInst->offset) <<2) );

				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LT, DELAYREG1, 0, 0, address) );

				PC = PC + 4;
		}

		void deBGEZ(void* arg)
		{
				unsigned address = PC + 4 + (((signed short)pInst->offset) << 2);

				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GE, DELAYREG1, 0, 0, address) );

				PC = PC + 4;
		}

		void deBLTZL(void* arg);
		void deBGEZL(void* arg);
		void deTGEI(void* arg);
		void deTGEIU(void* arg);
		void deTLTI(void* arg);
		void deTLTIU(void* arg);
		void deTEQI(void* arg);
		void deTNEI(void* arg);

		void deBLTZAL(void* arg)
		{
				unsigned address = (PC + 4 + (((signed short)pInst->offset) <<2));
				((MIPSVBasicBlockBuilder*)arg)->add( LI(PC+8, 31) );		//$ra : 31
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(31, 31) );		//$ra : 31

				/**
				 * As delay slot will be executed first, so we should store
				 * the operand in a reg which will not be used in the delay slot
				 */
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rrs, pInst->rrs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rrs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(LT, DELAYREG1, 0, 0, address) );

				PC = PC + 4;
		}

		void deBGEZAL(void* arg)
		{
				unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);
				((MIPSVBasicBlockBuilder*)arg)->add( LI(PC+8, 31) );
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(31, 31) );
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rs, pInst->rs) );
				((MIPSVBasicBlockBuilder*)arg)->add( MOV(pInst->rs, DELAYREG1) );

				pInst = (MIPSOpsFmt*)(PC+4);
				deTable[pInst->op].f(arg);

				((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(GE, DELAYREG1, 0, 0, address) );

				PC = PC + 4;
		}

		void deBLTZALL(void* arg);
		void deBGEZALL(void* arg);
		void deSYNCI(void* arg);

		void deMFC1(void* arg)
		{
				//deUndef(arg);
				//FST_MEM(pInst->rd, WORD, 0, pState->get(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rd, WORD, 0, pState->get(pInst->rt)) );
				((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->get(pInst->rt), WORD, pInst->rt) );
				//LD_MEM( 0, pState->get(pInst->rt), WORD, pInst->rt );        
				((MIPSVBasicBlockBuilder*)arg)->add( PUT(pInst->rt, pInst->rt) );
		}

		void deCFC1(void* arg)
		{
				//dummy
				//printf("use instruction CFC1\n");
				//exit(1);
				//((MIPSVBasicBlockBuilder*)arg)->add( FST(pInst->rd, WORD, 0, interp_state->get(pInst->rt)) );
		}

		void deMTC1(void* arg)	//added newly
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( GET(pInst->rt, pInst->rt) );
				((MIPSVBasicBlockBuilder*)arg)->add( ST(pInst->rt, WORD, 0, pState->get(pInst->rt)) );
				//ST_MEM(pInst->rt, WORD, 0, pState->get(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FLD(0, pState->get(pInst->rt), WORD, pInst->rd) );
				//LD_MEM( 0, pState->get(pInst->rt), WORD, pInst->rd );        
		}

		void deCTC1(void* arg)
		{
				//dummy
				//printf("use instruction CTC1\n");
				//exit(1);
				//((MIPSVBasicBlockBuilder*)arg)->add( FLD(0, interp_state->get(pInst->rt), WORD, pInst->rd) );
		}

		void deBC1(void* arg)
		{
				//printf("PC 0x%08x, \n", PC);

				if(pInst->rt == 1)
				{
						//printf("BC1T\n");

						unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);

						((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1));
						//LD_MEM( 0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1 );        

						pInst = (MIPSOpsFmt*)(PC+4);
						deTable[pInst->op].f(arg);

						((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(NE, 0, DELAYREG1, 0, address) );
						PC = PC + 4;
				}
				else if(pInst->rt == 0)
				{
						//printf("BC1F\n");

						unsigned int address = PC + 4 + ((signed short)pInst->offset << 2);

						((MIPSVBasicBlockBuilder*)arg)->add( LD(0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1));
						//LD_MEM( 0, pState->fpGet(MIPSProcessorState::$fcc), WORD, DELAYREG1 );        

						pInst = (MIPSOpsFmt*)(PC+4);
						deTable[pInst->op].f(arg);

						((MIPSVBasicBlockBuilder*)arg)->add( BRANCH(EQ, 0, DELAYREG1, 0, address) );

						PC = PC + 4;
				}
		}

		void deADD_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FADDS() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deADD_D(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FADDD() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deSUB_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FSUBS() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deSUB_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FSUBD() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deMUL_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FMULS() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deMUL_D(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FMULD() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deDIV_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FDIVS() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deDIV_D(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rt));
				((MIPSVBasicBlockBuilder*)arg)->add( FDIVD() );
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deABS_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FABSS());
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deABS_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FABSD());
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deMOV_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deMOV_D(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
		}

		void deNEG_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETS(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FNEGS());
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTS(pInst->ze));
		}

		void deNEG_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FGETD(pInst->rd));
				((MIPSVBasicBlockBuilder*)arg)->add( FNEGD());
				((MIPSVBasicBlockBuilder*)arg)->add( FPUTD(pInst->ze));
				//printf("PC: 0x%08x: neg.d\n", PC);
		}

		void deCVT_W_D(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, DOUBLE, pInst->ze, WORD) );
		}

		void deC_EQ_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(EQ, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
		}

		void deC_EQ_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(EQ, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
				//printf("PC:0x%08x, c.eq.d\n", PC);
		}

		void deC_ULE_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
		}

		void deC_LT_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(BE, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
		}

		void deC_LT_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(BE, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
				//printf("PC:0x%08x, c.lt.d\n", PC);
		}

		void deC_LE_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPS(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
		}

		void deC_LE_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCMPD(NA, pInst->rd, pInst->rt, MIPSProcessorState::$fcc) );
				//printf("PC:0x%08x, c.le.d\n", PC);
		}

		void deCVT_D_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, FLOAT, pInst->ze, DOUBLE) );
		}

		void deCVT_W_S(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, FLOAT, pInst->ze, WORD) );
		}

		void deCVT_S_W(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, WORD, pInst->ze, FLOAT) );
		}

		void deCVT_D_W(void* arg)
		{
				//deUndef(arg);
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, WORD, pInst->ze, DOUBLE) );
		}

		void deCVT_S_D(void* arg)
		{
				((MIPSVBasicBlockBuilder*)arg)->add( FCONV(pInst->rd, DOUBLE, pInst->ze, FLOAT) );
		}

		void deUndef(void* arg)
		{
				printf("0x%08x:\t", PC);
				printf("Undef instruction: 0x%08x\n", *(int*)arg);
				exit(1);
		} 
}

void MIPSInterpreter::delaySlot( XTMemAddr addr )
{
		//MIPSOpsFmt* inst = (MIPSOpsFmt*)(mm_->map(PC));
		MIPSOpsFmt* inst = (MIPSOpsFmt*)(PC);
		deTable[inst->op].f( inst );
}

XTInt32 MIPSInterpreter::initStack(XTMemAddr sp)
{
		interp_state->put( 29, sp ); 
		return 0;
}

XTMemAddr MIPSInterpreter::decode(XTMemAddr at, VBlockBuilder *bb)
{
		PC = at;
		//			pInst = (MIPSOpsFmt*)(mm_->map(PC));
		pInst = (MIPSOpsFmt*)(PC);
		pState = (MIPSProcessorState*)(interp_state);
		//pShadowPage = shadow_page;
		deTable[pInst->op].f( bb );

		return (PC+4); 
}
